俗話說:「一千個人,就有一千種程式碼的寫法」,而且我們身在 JavaScript 的世界中,一段程式碼可以用各種不同的方式來表達,例如該用單引號或雙引號、空格或 Tab 等等的議題。
如果深入到 React 中,會有使用 map
渲染 component 時忘記加 key
,或是者是 <Index></Index>
沒有 children 卻不使用 close tag 等情況,而且有一些程式碼可能會導致 bug,或是這種寫法可能會引發一些問題,但是難以發現。再加上導入 TypeScript、Next.js 後,有數不清的規則,只有文件規範一般人根本無法完全記住。
為了解決這些問題,所以我們需要 ESLint 幫助我們規範程式碼的撰寫方式,團隊都必須遵照規範,讓團隊成員不會寫出 ninja code。
除了 ESLint 之外,為了讓團隊撰寫的程式碼風格更為一致,還會再導入 Prettier,處理像是:
以上等等的問題都是我們經常遇到的問題,如同文章開頭所述,每個人都有自己的程式碼風格,隨著專案逐漸擴大,將會使得程式碼不易維護。所以使用 ESLint 搭配 Prettier 可以讓程式自動幫我們維護程式碼的風格,免得還需要用人工的方式檢驗程式碼,不僅沒有效率,而且也較不可靠。
在這篇文章中將會介紹如何在 Next.js + TypeScript 的環境中導入 ESLint 跟 Prettier 的設定,並且在文末將會介紹如何 husky 這項工具,在每次 git commit
時都可以自動幫助我們檢查是否符合 ESLint 及 Prettier 的規範,讓開發事半功倍。
首先,我們先來建立一個新的專案,可以使用以下指令 npx
或 yarn
開啟一個 Next.js + TypeScript 的專案:
npx create-next-app --typescript
# or
yarn create next-app --typescript
在 Next.js 11 版以後,ESLint 已經成為專案的標配,在建立完專案後就可以在資料夾中看到 .eslintrc.json
。預設的 ESLint 內容如下, 這是 Next.js 規範的 ESLint:
{
"extends": "next/core-web-vitals"
}
這個設定基本上已經包含了大部分 React 會需要的 ESLint plugin:
[eslint-plugin-react](https://www.npmjs.com/package/eslint-plugin-react)
[eslint-plugin-react-hooks](https://www.npmjs.com/package/eslint-plugin-react-hooks)
[eslint-plugin-next](https://www.npmjs.com/package/@next/eslint-plugin-next)
如同這個設定的名稱所述,它將會禁止兩種會影響 core web vitals 的寫法,其 ESLint 的等級都設置為 error,因此絕對無法通過 lint:
No sync scripts
在 component 中使用 <script>
引入其他的 JavaScript 檔案時一定要加上 async
或 defer
,否則同步的 <script>
將會影響 component 的效能:
// bad
<script src="some.js"></script>
// good
<script src="some.js" defer></script>
// good
<script src="some.js" async></script>
還有另外一種合法的寫法是使用目前在實驗中的 next/script
,它也會讓在 component 中載入外部檔案變成非同步的:
import Script from "next/script";
const Home = () => {
return (
<div class="container">
<Script src="https://third-party-script.js"></Script>
<div>Home Page</div>
</div>
);
};
export default Home;
No html link for pages
這個規則禁止在 component 中使用原生 HTML 的 <a>
切換頁面,如果需要切換頁面,則是使用 next/link
提供的 <Link>
```javascript
// bad
<a href="/about">About Us</a>
// good
<Link href="/about">
```
如果是全新的 Next.js 專案,官方建議直接導入 next/core-web-vitals
,這個設定已經包含了 next
這個 config,你可能會在其他地方看到 extends
中同時包含 next/core-web-vitals
與 next
,這個是較為舊的寫法,大概是幾個月前 XD
首先,我們需要安裝以下兩個套件:
yarn add -D prettier eslint-config-prettier
因為 ESLint 已經包含程式碼 formatting 的規則,這些規則可能會與 Prettier 的設定發生衝突,所以為了解衝突,可以使用 eslint-config-prettier
關閉一些 ESLint 會與 Prettier 發生衝突的規則。
接著,我們需要為程式碼風格做一些配置,例如單引號、分號、tab 幾格、程式碼寬度等等,至於其他設定就看團隊的需求了:
// .prettierrc
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"useTabs": false,
"printWidth": 120
}
然後我們需要在 .eslintrc.json
中設定 eslint-config-prettier
,在 extends
的最後一個位置加上 "prettier"
的設定,如此一來才能覆蓋 "next/core-web-vitals"
引入的 ESLint 設定:
// .eslintrc.json
{
"extends": [
"next/core-web-vitals",
"prettier"
],
}
最後,我們會在 package.json
中設定 prettier
的指令,為的是可以在文章後面串接 git hook。 團隊在開發時,一定會執行 git commit
將程式碼記錄在 git 上,這時可以觸發 git hook,同時跑 prettier 幫我們把所有的程式碼都「整理」過一次,如此一來可以確保推到 git 上的程式碼都是符合團隊規範的。
// package.json
{
"scripts": {
"prettier": "prettier '**/*.{js,jsx,ts,tsx}' --write"
}
}
@typescript-eslint/eslint-plugin
TypeScript 做為現在的趨勢,許多專案都是用 TypeScript 撰寫,強型別能夠帶來非常多的好處,能讓前端的應用更為穩健,可維護性也更高。但是 TypeScript 也是有許多需要規範的寫法,所以我們需要另外設置 @typescript-eslint/eslint-plugin
,讓它幫我們糾察出 TypeScript 程式碼不符合規範的地方。
你可能會聽過 TSLint 這個套件,但是現在如果上 GitHub 上看 TSLint 這個 repo,它已經被 archived 了,主要是因為 ESLint 的處理效能比 TSLint 更好,而且許多專案都仍然用 ESLint,所以最後官方團隊就把 TSLint 移植到
@typescript-eslint/eslint-plugin
上面了。
首先,我們使用以下指令安裝套件:
yarn add -D @typescript-eslint/eslint-plugin
然後,同樣在 .eslintrc.json
設定 @typescript-eslint/eslint-plugin
:
{
"extends": [
"next/core-web-vitals",
"plugin:@typescript-eslint/recommended",
"prettier"
],
}
git commit
時執行 ESLint 與 Prettierhusky (哈士奇) 是一個容易設定 git hook 的套件,像是我們希望在 pre-commit
時觸發 eslint 與 prettier,就可以透過 husky 來幫我們執行。然而,如果 prettier 跟 ESLint 每次 commit 時都需要處理在專案中所有的檔案,將會耗費非常多的時間在這些事情上,我們當然不會希望這樣的情況發生,難以想像這樣的開發流程。
所以,為了讓開發體驗更好,希望在 commit 時一樣可以讓 husky 幫我們觸發 git hook,但可以只針對在 stage 的檔案執行 ESLint 與 prettier。廣大的社群已經想過一樣的情況,有相對應的解決方案,那就是 lint-staged 這個套件。
我們使用以下指令安裝 husky 跟 lint-staged 這兩個套件:
yarn add -D husky lint-staged
在安裝完畢後,接著初始化 hucky 的環境:
yarn husky install
你會在專案資料夾中看到多了 .husky 這個資料夾,在 hucky 7 以後設定 git hook 的方式不太一樣,以前在前端我們可以寫在 package.json 裡面,但後來變成放在 .hucky 資料夾裡面,好處是讓設定更加彈性,可以直接在裡面寫 shell script。
接著,我們想要在 commit 時觸發 prettier 跟 eslint 兩個功能,可以使用以下指令建立 git hook,在 pre-commit 的時候會執行 lint-staged 這個指令,並且只針對在 git stage 的檔案做處理:
yarn husky add .husky/pre-commit "yarn lint-staged"
最後,我們需要設定 lint-staged 會執行哪些指令,可以直接在 package.json 這個檔案中設定跑已經設定好的 prettier 指令,以及 eslint 指令。
package.json
{
"lint-staged": {
"**/*.{ts,tsx,js,jsx}": [
"yarn prettier",
"eslint"
]
}
}
也許你會想問為什麼這邊不是用 yarn lint
這個指令,yarn lint
對應是 next lint
,但我們不能使用它,而是要用原生的 eslint
。
這是一個存在於 next.js 官方的 GitHub issue ,在 next.js 11.1.2 版本之前在 lint-staged
使用 yarn lint
會發生錯誤,目前在 11.1.3 版可以用原生的 eslint
指令解決,未來還需要等待更新的版本發布, 也許才能解決 lint-staged
不能執行 next lint
的問題。
以上就是在 next.js 11.1.2 版本下設定 ESLint + Prettier + TypeScript + husky 的流程,現在我們知道了如何在專案中加入這些設定,讓團隊開發時能夠寫處更好維護的程式碼,讓程式幫我們維護程式。